package cn.com.header.zbpk.account.service.impl;

import cn.com.header.core.IPage;
import cn.com.header.core.ISort;
import cn.com.header.core.sort.Sorter;
import cn.com.header.core.support.web.ResultCode;
import cn.com.header.zbpk.account.entity.*;
import cn.com.header.zbpk.account.mapper.*;
import cn.com.header.zbpk.account.model.*;
import cn.com.header.zbpk.account.service.IUserService;
import cn.com.header.zbpk.base.mapper.ISectionMapper;
import cn.com.header.zbpk.base.mapper.ISubjectMapper;

import cn.com.header.zbpk.exception.ServiceException;
import cn.com.header.zbpk.model.AuthorityMode;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author luohaidian
 * @date 2017-11-14
 * @time 10:00
 */
@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private IUserMapper iUserMapper;

    @Autowired
    private IRoleMapper iRoleMapper;

    @Autowired
    private IUserRoleMapper iUserRoleMapper;

    @Autowired
    private ISectionMapper iSectionMapper;

    @Autowired
    private ISubjectMapper iSubjectMapper;


    @Autowired
    private IAuthorityMapper iAuthorityMapper;


    @Override
    public int loadCount(User user, String keyword) {
        return iUserMapper.loadCount(user, keyword);
    }


    @Override
    public Map<String, Object> loadWithRole(User user, String keyword, Long roleId, Set<ISort> sortSet, IPage page) {
        Long schoolId = user.getSchoolId();
        if (Objects.nonNull(schoolId)){
            if (Objects.nonNull(roleId)){
                Role role = new Role(roleId);
                role.setSchoolId(schoolId);
                if (iRoleMapper.loadCount(role) == 0){
                    throw new ServiceException(ResultCode.PARAM_ERROR, "该学校不存在ID为[" + roleId + "]的角色名！！！");
                }
            }
        }
        Role role = new Role();
        role.setSchoolId(schoolId);
        Set<String> fields = Sets.newHashSet("user.id", "user.username", "user.create_time AS createTime","user.name",
                "user.job_number AS jobNumber", "user.telephone", "user.email", "user.enabled");
        List<Role> roleList = iRoleMapper.loads(role, null, Sets.newHashSet(new Sorter("id", true)), null);
        int totalRecordCount = iUserMapper.loadCount(user, keyword);
        List<UserExtend> userExtendList = totalRecordCount == 0 ? Collections.EMPTY_LIST : iUserMapper.customLoads(user, fields, sortSet, page, keyword);
        if (Objects.nonNull(roleId)){
            totalRecordCount = iUserMapper.loadCountBy(user.getEnabled(), roleId, null, keyword, user.getSchoolId());
            userExtendList = totalRecordCount == 0 ? Collections.EMPTY_LIST : iUserMapper.loadsByRoleId(roleId, null, user.getEnabled(), user.getSchoolId(), fields, sortSet, page, keyword);
        }

        Map<String, Object> dataMap = Maps.newHashMapWithExpectedSize(6);
        dataMap.put("roleList", roleList);
        dataMap.put("totalRecordCount", totalRecordCount);
        dataMap.put("userList", userExtendList);
        return dataMap;
    }

    @Override
    public Optional<User> loadByPK(Long id, Set<String> fields) {
        User user = iUserMapper.loadByPK(id, fields);
        if (Objects.isNull(user)){
            return Optional.empty();
        }
        return Optional.of(user);
    }

    @Override
    public List<UserExtend> loads(User user, Set<ISort> sortSet, IPage page, String keyword) {
        List<UserExtend> userExtendList = iUserMapper.customLoads(user, null, sortSet, page, keyword);
        if (userExtendList.isEmpty() || Objects.isNull(userExtendList)){
            return Collections.EMPTY_LIST;
        }
        return userExtendList;
    }



    private User transformUserProperty(String username, User user) {
        if (Objects.isNull(user)) {
            user = new User();
        }
        user.setUsername(username);
        return user;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (Objects.isNull(username)){
            throw new UsernameNotFoundException("用户名不存在！");
        }
        User user = transformUserProperty(username, null);
        List<User> users = iUserMapper.loads(user, null, null, null,null);
        if (users.isEmpty()){
            throw new UsernameNotFoundException("用户名 ["+username+"] 不存在");
        }
        user = users.get(0);
        Set<String> authorityIdSet = iAuthorityMapper.loadByUserId(user.getId(), AuthorityMode.INTERCEPTOR);
        authorityIdSet.add(Authority.COMMON_AUTH_ACCESS_ID);
        Function<String, GrantedAuthority> function = s -> (GrantedAuthority) () -> s;
        Set<GrantedAuthority> grantedAuthorities = authorityIdSet.stream().map(function).collect(Collectors.toSet());
        return new SecurityUserImpl(user.getId(),user.getName(),user.getSchoolId(),user.getUsername(),user.getPassword(), user.getEnabled(),
                true, true, true, grantedAuthorities);
    }

    public static class SecurityUserImpl extends org.springframework.security.core.userdetails.User implements SecurityUser {

        private Long id;
        private String name;
        private Long schoolId;

        public SecurityUserImpl(Long id, String name, Long schoolId, String username, String password, boolean enabled,
                            boolean accountNonExpired, boolean credentialsNonExpired,
                            boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities){
            super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
            this.id = id;
            this.name = name;
            this.schoolId = schoolId;
        }

        @Override
        public Long getId() {
            return id;
        }
        @Override
        public String getName(){
            return name;
        }
        @Override
        public Long getSchoolId(){
            return schoolId;
        }
    }

}
